package cn.bdqn.util;


import cn.bdqn.filter.JwtTokenFilter;
import cn.bdqn.filter.JwtVerifyFileter;
import cn.bdqn.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;


/**
 * @ProjectName: springbootSecurity
 * @Package: cn.cn.bdqn.security.util
 * @Author: huat
 * @Date: 2019/12/14 8:06
 * @Version: 1.0
 */

/**
 * 开启security注解支持
 *
 * @EnableWebSecurity EnableGlobalMethodSecurity  方法级授权
 * (securedEnabled=true) 开启@Secured 注解过滤权限
 * (jsr250Enabled=true)开启@RolesAllowed 注解过滤权限
 * (prePostEnabled=true) 使用表达式时间方法级别的安全性         4个注解可用
 * @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)
 */
@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true)
//@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)
public class SpringSercurityConfig extends WebSecurityConfigurerAdapter {
    /* @Autowired
     UserService1 userService;*/
    @Autowired
    UserService userService;
    @Autowired
    private RsaKeyProperties rsaKeyProperties;


    /**
     * 将security中加密方式注入到spring容器中
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 解决跨域
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        //指定允许跨域的请求(*所有)：http://wap.ivt.guansichou.com
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "X-User-Agent", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /**
     * 将账号密码设置在内存当中
     *
     * @param auth
     * @throws Exception
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                //将UserDetailsService放到容器中
                .userDetailsService(userService)
                //加密方式放入
                .passwordEncoder(passwordEncoder());
    }

    //前后端分离时候使用
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //释放静态资源，指定资源拦截规则，
        // 指定自定义认证页面，指定退出认证配置，csrf（跨域伪造请求）配置
            http
                .csrf()
                .disable()//关闭csrf（跨域伪造请求）
                .cors()
                .and().servletApi().disable()
                .requestCache().disable()
                .authorizeRequests()
                .antMatchers("/index").hasAnyRole("ADMIN")
                .antMatchers("/test").hasRole("TEST")
                 .anyRequest().authenticated()//其他资源需要认证
                .and()
                .addFilter(new JwtTokenFilter(super.authenticationManager(),rsaKeyProperties))
                .addFilter(new JwtVerifyFileter(super.authenticationManager(),rsaKeyProperties))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//禁用session
                ;

    }
}
